/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "Wed_framework_config.h"
#include "Wed_dev.h"
#include "uart/Wed_uart.h"
#include "gpio/Wed_gpio.h"
#include "net/netdev/Wed_netdev.h"
#include "phy/Wed_phy.h"

/*******************************************************************************
 * Static
 ******************************************************************************/
static struct Wed_list_head __g_dev_list;
static struct Wed_mutex     __g_dev_list_lock;

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 设备添加函数
 */
static int __dev_add(struct Wed_dev *p_dev){
    int ret = 0;

    ret = Wed_mutex_lock(&__g_dev_list_lock, 5000);
    if (ret != 0) {
        return ret;
    }

    Wed_list_node_add_tail(&p_dev->node, &__g_dev_list);

    Wed_mutex_unlock(&__g_dev_list_lock);

    return ret;
}

/**
 * \brief 设备链表初始化
 *
 * @return 成功返回 0
 */
int Wed_dev_list_init(void){
    int ret;

    Wed_list_head_init(&__g_dev_list);

    ret = Wed_mutex_init(&__g_dev_list_lock);
    if (ret != 0) {
        return ret;
    }

    ret = Wed_uart_list_init();
    if (ret != 0) {
        return ret;
    }

    ret = Wed_gpio_list_init();
    if (ret != 0) {
        return ret;
    }

    ret = Wed_phy_list_init();
    if (ret != 0) {
        return ret;
    }

    return Wed_netdev_list_init();
}

/**
 * \brief 设备初始化并添加
 *
 * @param p_dev      设备结构体
 * @param p_dev_name 设备名
 * @param type       设备类型
 * @param p_opts     设备操作函数
 * @param p_usr_data 用户数据
 *
 * @return 成功返回 0
 */
int Wed_dev_init_add(struct Wed_dev      *p_dev,
                     char                *p_dev_name,
                     int                  type,
                     struct Wed_dev_opts *p_opts,
                     void                *p_opts_arg){
    strcpy(p_dev->name, p_dev_name);

    p_dev->type       = type;
    p_dev->p_opts     = p_opts;
    p_dev->p_opts_arg = p_opts_arg;

    Wed_list_node_init(&p_dev->node);

    return __dev_add(p_dev);
}

/**
 * \brief 通过设备名字寻找设备
 *
 * @param p_dev_name 设备名
 *
 * @return 找到返回设备结构体，没找到返回 NULL
 */
struct Wed_dev *Wed_dev_find_by_name(char *p_dev_name){
    int                   ret;
    struct Wed_list_node *p_node = NULL;
    struct Wed_dev       *p_dev  = NULL;

    ret = Wed_mutex_lock(&__g_dev_list_lock, 5000);
    if (ret != 0) {
        return NULL;
    }

    Wed_list_for_each_node(p_node, &__g_dev_list){
        p_dev = WED_CONTAINER_OF(p_node, struct Wed_dev, node);
        if (strcmp(p_dev->name, p_dev_name) == 0) {
            Wed_mutex_unlock(&__g_dev_list_lock);

            return p_dev;
        }
    }

    Wed_mutex_unlock(&__g_dev_list_lock);

    return NULL;
}

/**
 * \brief 设备写函数
 *
 * @param p_dev    设备结构体
 * @param p_data   要写的数据缓存
 * @param data_len 要写的数据长度
 *
 * @return 返回实际写的数据长度
 */
int Wed_dev_write(struct Wed_dev *p_dev, uint8_t *p_data, uint32_t data_len){
    if ((p_dev == NULL) ||
            (p_data == NULL) ||
            (data_len == 0)) {
        return -WED_EINVAL;
    }

    if ((p_dev->p_opts == NULL) || (p_dev->p_opts->p_fn_write == NULL)) {
        return -WED_ENOSUPPORT;
    }

    return p_dev->p_opts->p_fn_write(p_dev->p_opts_arg, p_data, data_len);
}
